#ifndef __VBO_H__
#define __VBO_H__

#include "stdafx.h"
#include <vector>
#include "vec3.h"
#include "vec2.h"

namespace GeorgeLib
{
	///	@brief A data structure for the information for each %vertex
	///	@details
	///	Conatins the coordinates for the vertices, texture coordinates,
	///	normal coordinates and RGBA color values

	struct Vertex
	{
		///	vertex coordinates
		float pos[3];

		///	texture coordinates
		float texcoord[2];

		///	normal coordinates
		float normal[3];

		///	color data
		float color[4];

		///	padding to make the struct 64 bytes for efficiency
		GLubyte padding[16];
	};

	/// @brief
	/// Stores Vertex data, id of the generated
	///	[Vertex Buffer Object](http://en.wikipedia.org/wiki/Vertex_Buffer_Object)
	///	, and the primitive drawing mode.

	///	@details
	/// VBO_Data knows whether its vertices contains normal data,
	/// texture coordinate data and color data.

	class DLLEXPORT VBO_Data
	{
	public:

		/// The array of @link Vertex Vertices @endlink
		vector<Vertex> vertices;

		/// id of the Vertex Buffer Object
		/**	@see http://www.opengl.org/sdk/docs/man/html/glGenBuffers.xhtml	**/
		uint	id,

			/// mode in which the vertices are to be drawn
			/**	@see http://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml	**/
			mode;

		///	is true when @link Vertex Vertices @endlink has normal coordinates data
		bool	hasNormal,
			///	is true when @link Vertex Vertices @endlink has texture coordinates data
			hasTexCoord,
			///	is true when @link Vertex Vertices @endlink has color data
			hasColor;

		/// constructor
		VBO_Data()
			: hasTexCoord(false)
			, hasNormal(false)
			, hasColor(false)
		{};

		/// destructor
		~VBO_Data() {};
	};

	/// @brief
	/// Manages the creating and rendering of [Vertex Buffer Objects (VBOs)]
	/// (http://en.wikipedia.org/wiki/Vertex_Buffer_Object)

	///	@details
	/// Provides an easy interface to create, store and use VBOs.
	/// Enables the adding of @link Vertex Vertices @endlink using methods similar to OpenGL's deprecated
	/// direct vertex API.

	///	\n\n
	///	How to use :
	/// @code
	///		VBO vbo;						// Create a VBO
	///
	///		void Init(void)
	///		{
	///			vec3 vertices =				// Specify vertices
	///			{
	///				vec3(0,0,0), vec3(1,0,0), vec3(1,1,0)
	///			};
	///
	///			vbo.Begin(GL_TRIANGLES);	// Begin pushing in vertices
	///			vbo.AddTriangle(vertices);	// Push in our vertices
	///			vbo.End();					// End and upload vertice data
	///		}
	///
	///		void Draw(void)
	///		{
	///			vbo.Draw();					// Render vertices
	///		}
	/// @endcode

	class DLLEXPORT VBO
	{
	private:

		/// array of VBO_Data. VBO_Data contains vertice information, drawing mode and a VBO id.
		vector<VBO_Data*> vbos;

		/// boolean to check if \c VBO::Begin() has been called
		bool bAcceptingVertexData;

	public:

		/// constructor
		VBO(void) : bAcceptingVertexData(false) {};

		/// destructor
		~VBO(void);

		/// Create a new Vertex Buffer Object, and start the process of adding vertices to it.
		/** This function will call OpenGL to generate a new VBO.
			A new VBO_Data object will be created, the id of the Vertex Buffer Object and the
			drawing mode will be passed in.
			@param mode the type of primitive to be drawn, same as \c glBegin(GLenum mode)
			@return the generated id of the Vertex Buffer Object. if \c VBO::Begin()
			has already been called, returns 0
			@note For info on 'GLenum mode', see
			https://www.opengl.org/sdk/docs/man2/xhtml/glBegin.xml
			@note Only call 'VBO::AddVertex, \c VBO::AddNormal(), \c VBO::AddTexCoord(), \c VBO::AddColor()
			and \c VBO::SetColor() after calling this function	**/
		GLuint Begin(GLenum mode);

		/// End the process of adding vertices to the Vertex Buffer Object.
		/**	Passes the vertex data to the video device, and tells OpenGL how the data
			will be accessed.
			@param usage tells OpenGL how the vertice data will be used,
			@note For info on 'GLenum usage', see
			http://www.opengl.org/sdk/docs/man/docbook4/xhtml/glBufferData.xml
			@note Any calls adding vertex data will not apply after this function
			has been called	**/
		void End(GLenum usage = GL_STATIC_DRAW);

		/// Start the process of re-adding vertices to an already generated Vertex Buffer Object.
		/** All local vertice data in the VBO_Data referencing the specified VBO will be erased,
			and then the process of adding new vertice data to the VBO enabled.
			@param id the generated id of the Vertex Buffer Object	**/
		void UpdateBegin(GLuint id);

		/// End the process of re-adding vertices to an already generated Vertex Buffer Object
		/**	@param id the generated id of the Vertex Buffer Object
			@see VBO::End()	**/
		void UpdateEnd(GLuint id);

		/// Render out the vertices of the VBOs stored
		void Draw(void);

		/// Add a vertex with a \c vec3 object
		void AddVertex(vec3 v);

		/// Add a vertex with 3 \c float values
		void AddVertex(float x, float y, float z);

		/// Add a vertex with a \c float array of 3 values
		void AddVertex(float *v);

		/// Add a normal vertex with a \c vec3 object
		void AddNormal(vec3 v);

		/// Add a normal vertex with 3 \c float values
		void AddNormal(float x, float y, float z);

		/// Add a normal vertex with an array of 3 \c float values
		void AddNormal(float *v);

		/// Add a texture coordinate vertex with a \c vec2 object
		void AddTexCoord(vec2 v);

		/// Add a texture coordinate vertex with 2 \c float values
		void AddTexCoord(float u, float v);

		/// Add a texture coordinate vertex with a \c float array of 2 values
		void AddTexCoord(float *v);

		/// Add a color vertex with a \c vec3 object and a \c float
		/** @param v RGB color values for the vertices in a vec3 object
			@param a alpha value for the vertices	**/
		void AddColor(vec3 v, float a = 1.0f);

		/// Add a color vertex with 4 \c float values
		/** @param r, g, b, a RGBA color values for the vertices **/
		void AddColor(float r, float g, float b, float a = 1.0f);

		/// Add a color vertex with a \c float array of 4 values
		void AddColor(float *v);

		/// Sets the color for every vertex currently in this VBO
		/** @note Call this function between \c VBO::Begin() and \c VBO::End()
			@note This functions only edits the color value of vertices specified
			before this call. All other vertices added will not have
			their color values edited by this call
			@param vbo_id the generated id of the Vertex Buffer Object
			@param r, g, b, a RGBA color values for the vertices	**/
		void SetColor(GLuint vbo_id, float r, float g, float b, float a = 1.0f);
	};
} // namespace GeorgeLib

#endif